/**
 * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springblade.modules.monitor.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.annotations.ApiModelProperty;
import org.springblade.common.constant.HistoryTableEnum;
import org.springblade.common.constant.OperatingSystemEnum;
import org.springblade.common.tool.CommonUtil;
import org.springblade.common.tool.ServerMonitorUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.modules.monitor.dto.ChartDTO;
import org.springblade.modules.monitor.dto.DiskDTO;
import org.springblade.modules.monitor.dto.DiskMetadata;
import org.springblade.modules.monitor.mapper.HostInfoMapper;
import org.springblade.modules.monitor.mapper.NetEquipMapper;
import org.springblade.modules.monitor.mapper.WorkOrderMapper;
import org.springblade.modules.monitor.pojo.*;
import org.springblade.modules.monitor.service.IHostInfoService;
import org.springblade.modules.monitor.vo.EquipKind;
import org.springblade.modules.monitor.vo.HostInfoVO;
import org.springblade.modules.monitor.vo.ItemChartResult;
import org.springblade.modules.monitor.vo.ServerDetailInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import static org.springblade.common.tool.CommonUtil.transferHealthyValue;

/**
 *  服务实现类
 *
 * @author Blade
 * @since 2020-05-17
 */
@Service
public class HostInfoServiceImpl extends ServiceImpl<HostInfoMapper, HostInfoVO> implements IHostInfoService {
	@Autowired
	private HostInfoMapper hostInfoMapper;

	@Autowired
	private NetEquipMapper netEquipMapper;

	@Autowired
	private WorkOrderMapper workOrderMapper;

	@Override
	public ServerDetailVO getDetail(Long interfaceid) {

		ServerDetailVO server = new ServerDetailVO();
		//获取 服务器基础信息
		HostInfoVO hostInfo = hostInfoMapper.getDetail(interfaceid);
		EquipKind hostKind = hostInfoMapper.getHostKind(interfaceid).get(0);
		server.setHost(hostInfo.getHost());
		server.setIp(hostInfo.getIp());
		server.setPort(hostInfo.getPort());
		server.setManageStatus(hostInfo.getStatus());
		server.setManageType(hostInfo.getType());
		//查看system.uname中是否包含 先转成大写  WINDOWS
		//操作系统 operatingSystem
		//操作系统描述信息 systemDesc
		List<Map<String, Object>> datacenters = hostInfoMapper.getHostidByGroupName("Datacenter");
		List<Map<String, Object>> hosts = datacenters.stream().filter(x -> Long.valueOf(x.get("hostid").toString()).equals(hostInfo.getHostid())).collect(Collectors.toList());
		Map<String, List<Map<String, Object>>> strIntDoubleValue = getStrIntDoubleValue(hostInfo);
		List<Map<String, Object>> strValues = strIntDoubleValue.get("strValues");
		List<Map<String, Object>> intValues = strIntDoubleValue.get("intValues");
		List<Map<String, Object>> values = strIntDoubleValue.get("values");
		// linux 或 windows
		server = ServerMonitorUtil.transferServer(server, strValues, intValues, values);
		//工单的数量
		Integer alertCount = workOrderMapper.selectCountByHostname(hostInfo.getHost());
		server.setHealthyValue(transferHealthyValue(alertCount));
		return server;

	}

	@Override
	public IPage<HostInfoVO> selectHostInfoPage(IPage<HostInfoVO> page, HostInfoVO hostInfoVO) {
		Query query = new Query();
		query.setCurrent(1);
		query.setSize(10000);
		IPage<HostInfoVO> tempPage = Condition.getPage(query);
		List<EquipKind> hostKinds = hostInfoMapper.getHostKind(null);
		HostInfoVO tempHostInfoVO = new HostInfoVO();
		BeanUtils.copyProperties(hostInfoVO, tempHostInfoVO);
		tempHostInfoVO.setStatus(null);
		List<HostInfoVO> hostInfoVOS = baseMapper.selectHostInfoPage(tempPage, tempHostInfoVO);
		hostInfoVOS.forEach(x->{
			hostKinds.forEach(y->{
				if(x.getHostid().equals(y.getHostid())){
					if(!StringUtils.isEmpty(y.getEquipKind())){
						x.setServerKind(y.getEquipKind());
					}
				}
			});
		});

		List<Map<String, Object>> datacenters = hostInfoMapper.getHostidByGroupName("Datacenter");
		hostInfoVOS.forEach(x->{
			//EXSI
			if(StringUtils.isEmpty(x.getServerKind())){
				datacenters.forEach(y->{
					if (x.getHostid().equals(Long.valueOf(y.get("hostid").toString()))){
						x.setServerKind("15");
					}
				});
			}
		});
		List<Long> powersStatus = new ArrayList<>();
		hostInfoVOS.forEach(x->{
			//为空的默认为虚拟主机
			if(StringUtils.isEmpty(x.getServerKind())){
				x.setServerKind("16");
				powersStatus.add(x.getHostid());
			}
		});

		//TODO 查询虚拟机状态，电源状态；以电源状态作为虚拟机可用状态
		if(!CollectionUtils.isEmpty(powersStatus)){
			List<Map<String, Object>> latestVMPowerStateValues = hostInfoMapper.getLatestVMPowerStateValue(powersStatus);
			for (Map<String, Object> latestVMPowerStateValue : latestVMPowerStateValues) {
				for (HostInfoVO infoVO : hostInfoVOS) {
					if(latestVMPowerStateValue.get("hostid").toString().equals(infoVO.getHostid().toString())){
						if(Integer.valueOf(latestVMPowerStateValue.get("value").toString())==1){
							infoVO.setStatus(0);
						}else{
							infoVO.setStatus(1);
						}

					}
				}

			}
		}

		//TODO 后台分页，不使用数据库分页
		List<HostInfoVO> collect = hostInfoVOS.stream().filter(x -> {
			if(StringUtils.isEmpty(hostInfoVO.getHost())&&null==hostInfoVO.getStatus()){
				return true;
			}

			if(!StringUtils.isEmpty(hostInfoVO.getHost())&&null!=hostInfoVO.getStatus()){
				return x.getHost().contains(hostInfoVO.getHost()) && x.getStatus().equals(hostInfoVO.getStatus());
			}
			if(!StringUtils.isEmpty(hostInfoVO.getHost())&&null==hostInfoVO.getStatus()){
				return x.getHost().contains(hostInfoVO.getHost());
			}

			if(StringUtils.isEmpty(hostInfoVO.getHost())&&null!=hostInfoVO.getStatus()){
				return x.getStatus().equals(hostInfoVO.getStatus());
			}
			return true;
		}).collect(Collectors.toList());

		page.setTotal(collect.size());
		//计算分页偏移量
		Long offset =  page.getCurrent() > 0 ? (page.getCurrent() - 1) * page.getSize() : 0;
		boolean endFlag = collect.size() < offset.intValue() + Integer.valueOf(String.valueOf(page.getSize()));
		int endIndex = 0;
		if(endFlag){
			endIndex = offset.intValue() + collect.size() - offset.intValue();
		}else {
			endIndex = offset.intValue() + Integer.valueOf(String.valueOf(page.getSize()));
		}
		return page.setRecords(collect.subList(offset.intValue(),endIndex));
	}

	@Override
	public List<ItemChartResult> getCpuOrMemoryInfo(ChartDTO chartDTO) {

		//由于ESXI、VM、实体机的计算方式不同，此处进行拆分
		Long interfaceid = chartDTO.getInterfaceid();
		EquipKind hostKind = hostInfoMapper.getHostKind(interfaceid).get(0);
		//由于自动发现不能进行标记；此处通过 组名进行判别
		Long startTime;
		Long endTime;
		if(null!=chartDTO.getStartTime()){
			startTime = CommonUtil.getSecondFromTime(chartDTO.getStartTime());
		}else{
			startTime = CommonUtil.getSecondFromTime(LocalDateTime.now().minusHours(3));
		}

		if(null!=chartDTO.getEndTime()){
			endTime = CommonUtil.getSecondFromTime(chartDTO.getEndTime());
		}else {
			endTime = CommonUtil.getSecondFromTime(LocalDateTime.now());
		}
		List<ItemChartResult> list = new ArrayList<>();
		if("11".equals(hostKind.getEquipKind())||"12".equals(hostKind.getEquipKind())){
			// linux 或 windows  默认从history种获取数据，若为空，从history_uint 获取数据
			list = netEquipMapper.getBaseItemInfo(chartDTO.getItemid(),startTime,endTime,HistoryTableEnum.history.name());
			if(!CollectionUtil.isNotEmpty(list)){
				list = netEquipMapper.getBaseItemInfo(chartDTO.getItemid(),startTime,endTime,HistoryTableEnum.history_uint.name());
			}
			list.forEach(x->{
				x.setValue(CommonUtil.fun2(x.getValue()));
				x.setUnit("%");
			});
		}else if(StringUtils.isEmpty(hostKind.getEquipKind())){
			// 虚拟机
			list = netEquipMapper.getBaseItemInfo(chartDTO.getItemid(),startTime,endTime,HistoryTableEnum.history_uint.name());
		}
		return list;
	}

	@Override
	public ExsiVO getEXSIdetail(Long interfaceid) {
		ExsiVO exsiVO = new ExsiVO();
		//获取 服务器基础信息
		HostInfoVO hostInfo = hostInfoMapper.getDetail(interfaceid);
		ExsiGeneralVO exsiGeneralVO = new ExsiGeneralVO();
		exsiGeneralVO.setHost(hostInfo.getHost());
		exsiGeneralVO.setIp(hostInfo.getIp());
		exsiGeneralVO.setPort(hostInfo.getPort());
		exsiGeneralVO.setManageStatus(hostInfo.getStatus());
		exsiGeneralVO.setManageType(hostInfo.getType());
		exsiVO.setExsiGeneralVO(exsiGeneralVO);

		Map<String, List<Map<String, Object>>> strIntDoubleValue = getStrIntDoubleValue(hostInfo);
		List<Map<String, Object>> strValues = strIntDoubleValue.get("strValues");
		List<Map<String, Object>> intValues = strIntDoubleValue.get("intValues");
		List<Map<String, Object>> values = strIntDoubleValue.get("values");
		//由于自动发现不能进行标记；此处通过 组名进行判别
		exsiVO = ServerMonitorUtil.getEXSIdetail(exsiVO, strValues, intValues, values);
		Integer alertCount = workOrderMapper.selectCountByHostname(hostInfo.getHost());
		exsiVO.getExsiGeneralVO().setHealthyValue(transferHealthyValue(alertCount));
		return exsiVO;
	}

	@Override
	public VMMachineVO getVMdetail(Long interfaceid) {
		VMMachineVO vmMachineVO = new VMMachineVO();
		//获取 服务器基础信息
		HostInfoVO hostInfo = hostInfoMapper.getDetail(interfaceid);
		VMMachineGeneralVO vmMachineGeneralVO = new VMMachineGeneralVO();
		vmMachineGeneralVO.setHost(hostInfo.getHost());
		vmMachineGeneralVO.setIp(hostInfo.getIp());
		vmMachineGeneralVO.setPort(hostInfo.getPort());
		vmMachineGeneralVO.setManageStatus(hostInfo.getStatus());
		vmMachineGeneralVO.setManageType(hostInfo.getType());

		Map<String, List<Map<String, Object>>> strIntDoubleValue = getStrIntDoubleValue(hostInfo);
		List<Map<String, Object>> strValues = strIntDoubleValue.get("strValues");

		String  hostname = "" ;
		for (Map<String, Object> strValue : strValues) {
			if("vmware.vm.hv.name[{$URL},{HOST.HOST}]".equals(strValue.get("key_"))){
				hostname = strValue.get("value").toString();
				break;
			}
		}

		Map<String, Object> latestValueByHostnameAndKey = hostInfoMapper.getLatestValueByHostnameAndKey(hostname, "vmware.hv.hw.cpu.freq[{$URL},{HOST.HOST}]", HistoryTableEnum.history_uint.name());
		vmMachineGeneralVO.setCoreFrequency(Long.valueOf(latestValueByHostnameAndKey.get("value").toString()));
		vmMachineVO.setVMMachineGeneralVO(vmMachineGeneralVO);
		List<Map<String, Object>> intValues = strIntDoubleValue.get("intValues");
		List<Map<String, Object>> values = strIntDoubleValue.get("values");
		vmMachineVO = ServerMonitorUtil.getVMMachinedetail(vmMachineVO, strValues, intValues, values);
		Integer alertCount = workOrderMapper.selectCountByHostname(hostInfo.getHost());
		vmMachineVO.getVMMachineGeneralVO().setHealthyValue(transferHealthyValue(alertCount));
		return vmMachineVO;
	}


	private Map<String,List<Map<String, Object>>> getStrIntDoubleValue(HostInfoVO hostInfo){
		Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();
		//使用异步线程，最长时间取决于以下三个方法查询的最长时间
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		FutureTask<List<Map<String, Object>>> strValuesFuture = new FutureTask<List<Map<String, Object>>>(
			() -> hostInfoMapper.getCommonLatestItemsValue(hostInfo.getHostid(), HistoryTableEnum.history_str.name())
		);
		FutureTask<List<Map<String, Object>>> intValuesFuture = new FutureTask<List<Map<String, Object>>>(
			() -> hostInfoMapper.getCommonLatestItemsValue(hostInfo.getHostid(), HistoryTableEnum.history_uint.name())
		);

		FutureTask<List<Map<String, Object>>> valuesFuture = new FutureTask<List<Map<String, Object>>>(
			() -> hostInfoMapper.getCommonLatestItemsValue(hostInfo.getHostid(), HistoryTableEnum.history.name())
		);
		executorService.submit(strValuesFuture);
		executorService.submit(intValuesFuture);
		executorService.submit(valuesFuture);

		List<Map<String, Object>> strValues = null;
		List<Map<String, Object>> intValues = null;
		List<Map<String, Object>> values = null;
		try {
			strValues = strValuesFuture.get();
			intValues = intValuesFuture.get();
			values = valuesFuture.get();
		} catch (InterruptedException e) {
			log.error("Future 服务器基础信息", e);
		} catch (ExecutionException e) {
			log.error("Future 服务器基础信息", e);
		}finally {
			executorService.shutdown();
		}
		resultMap.put("strValues",strValues);
		resultMap.put("intValues",intValues);
		resultMap.put("values",values);
		return resultMap;
	}
}
